
`include "common_header.verilog"

//  *************************************************************************
//  File : host_control_xl
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited. 
//  Copyright (c) 2014 Morethanip, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Francois Balay
//  info@morethanip.com
//  *************************************************************************
//  Description: Generic Host Controller for 40G MAC
//  Version    : $Id: host_control_xl.v,v 1.3 2017/04/03 15:39:06 dk Exp $
//  *************************************************************************

module host_control_xl (

   reset,
   clk,
   cs,
   rd,
   wr,
   sel,
   data_in,
   data_out,
   busy,
   reg_rd,
   reg_wr,
   reg_sel,
   reg_data_in,
   reg_data_out,
   mdio_rd,
   mdio_wr,
   mdio_busy,
   stat_rd,
   stat_busy,
   rst_status);

  
input   reset;                  //  Active Low Global Reset
input   clk;                    //  25MHz Host Interface Clock
input   cs;                     //  Chip Select
input   rd;                     //  Register Read Strobe
input   wr;                     //  Register Write Strobe
input   [7:0] sel;              //  Register Address
input   [31:0] data_in;         //  Write Data for Host Bus
output  [31:0] data_out;        //  Read Data to Host Bus
output  busy;                   //  Interface Busy
output  reg_rd;                 //  Register Read Strobe
output  reg_wr;                 //  Register Write Strobe
output  [7:0] reg_sel;          //  Register Address
output  [31:0] reg_data_in;     //  Write Data from Host Bus
input   [31:0] reg_data_out;    //  Read Data to Host Bus
output  mdio_rd;                //  MDIO Module Read Strobe
output  mdio_wr;                //  MDIO Module Write Strobe
input   mdio_busy;              //  MDIO busy
output  stat_rd;                //  Statistics registers access
input   stat_busy;              //  Statistics Counter read busy
output   rst_status;            //  Reset Status Register

reg     [31:0] data_out; 
reg     busy; 
reg     reg_rd; 
reg     reg_wr; 
reg     [7:0] reg_sel; 
reg     [31:0] reg_data_in; 
reg     mdio_rd; 
reg     mdio_wr; 
reg     stat_rd;
reg     rst_status; 

// TYPE STM_TYPE:
parameter STM_TYPE_IDLE           = 4'd 0;
parameter STM_TYPE_READ           = 4'd 1;
parameter STM_TYPE_WRITE          = 4'd 2;
parameter STM_TYPE_STAT_READ      = 4'd 3;
parameter STM_TYPE_STAT_WAIT      = 4'd 4;
parameter STM_TYPE_NEXT_CYCLE     = 4'd 5;
`ifdef MTIPM10_HOST_CONTROL_PIPE
parameter STM_TYPE_WAIT_CYCLE     = 4'd 6;
`endif
parameter STM_TYPE_READ_PHY_STAT1 = 4'd 7;
parameter STM_TYPE_MDIO_READ      = 4'd 8;
parameter STM_TYPE_MDIO_WRITE     = 4'd 9;
parameter STM_TYPE_MDIO_WWAIT     = 4'd 10;

reg     [3:0] state; 
reg     [3:0] nextstate; 
wire    cs_reg;         //  Chip Select
wire    rd_reg;         //  Register Read Strobe
wire    wr_reg;         //  Register Write Strobe
wire    [7:0] sel_reg;  //  Register Address

//  input registers
//  ---------------
always @(posedge reset or posedge clk)
   begin : process_1
   if (reset == 1'b 1)
      begin
      reg_data_in <= {32{1'b 0}};	
      reg_sel <= {8{1'b 0}};	
      end
   else
      begin
      reg_data_in <= data_in;	
      reg_sel <= sel;	
      end
   end

assign sel_reg = sel; 
assign cs_reg = cs; 
assign rd_reg = rd; 
assign wr_reg = wr; 

//  STM
//  ---
always @(posedge reset or posedge clk)
   begin : process_2
   if (reset == 1'b 1)
      begin
      state <= STM_TYPE_IDLE;	
      end
   else
      begin
      state <= nextstate;	
      end
   end

always @(state or sel_reg or mdio_busy or stat_busy or rd_reg or wr_reg or cs_reg)
   begin : process_3
   case (state)
   STM_TYPE_IDLE:
      begin
//  Read Status (16)
//  -----------
      if (stat_busy == 1'b 1 & cs_reg == 1'b 1 & rd_reg == 1'b 1 & sel_reg == 8'h 10)
         begin
         nextstate = STM_TYPE_READ_PHY_STAT1;	
         end
//  Read Statistic Counters at address 33..192 (0x84..0x2ff) and 0x380 ... 0x3ff  (0xe0..ff)
//  -----------------------
      else if (stat_busy == 1'b 1 & cs_reg == 1'b 1 & rd_reg == 1'b 1 & ((sel_reg > 8'h 20 & sel_reg < 8'h C0) | sel_reg > 8'h df) )
         begin
         nextstate = STM_TYPE_STAT_READ;	
         end
//  Read MDIO DATA Register (12,13,14,15)
//  -----------------------
      else if (stat_busy == 1'b 1 & cs_reg == 1'b 1 & rd_reg == 1'b 1 & 
                (sel_reg == 8'h 0c | sel_reg == 8'h 0d | sel_reg == 8'h 0e | sel_reg == 8'h 0f) )
         begin
         nextstate = STM_TYPE_MDIO_READ;	
         end
//  Write MDIO DATA Register
//  --------------------
      else if (cs_reg == 1'b 1 & wr_reg == 1'b 1 & 
                (sel_reg == 8'h 0c | sel_reg == 8'h 0d | sel_reg == 8'h 0e | sel_reg == 8'h 0f) )
         begin
         nextstate = STM_TYPE_MDIO_WRITE;	
         end
//  Other Write Accesses
//  --------------------
      else if (cs_reg == 1'b 1 & wr_reg == 1'b 1 )
         begin
         nextstate = STM_TYPE_WRITE;	
         end
//  Other Read Accesses
//  -------------------
      else if (stat_busy == 1'b 1 & cs_reg == 1'b 1 & rd_reg == 1'b 1 )
         begin
         nextstate = STM_TYPE_READ;	
         end
      else
         begin
         nextstate = STM_TYPE_IDLE;	
         end
      end
//  Read PHY Status
//  ---------------
   STM_TYPE_READ_PHY_STAT1:
      begin
      nextstate = STM_TYPE_NEXT_CYCLE;	
      end
//  Register Read
//  -------------
   STM_TYPE_READ:
      begin
      nextstate = STM_TYPE_NEXT_CYCLE;	
      end
   STM_TYPE_WRITE:
      begin
      nextstate = STM_TYPE_NEXT_CYCLE;	
      end
//  Statistic Counters Read
//  -----------------------
   STM_TYPE_STAT_READ:
      begin
      nextstate = STM_TYPE_STAT_WAIT;	
      end
   STM_TYPE_STAT_WAIT:
      begin
      if (stat_busy == 1'b 0)
         begin
         nextstate = STM_TYPE_NEXT_CYCLE;	
         end
      else
         begin
         nextstate = STM_TYPE_STAT_WAIT;	
         end
      end
//  MDIO Read
//  ---------
   STM_TYPE_MDIO_READ:
      begin
      if (mdio_busy == 1'b 1)
         begin
         nextstate = STM_TYPE_MDIO_READ;	
         end
      else
         begin
         nextstate = STM_TYPE_NEXT_CYCLE;	
         end
      end
//  MDIO Write
//  ----------
   STM_TYPE_MDIO_WRITE:
      begin
      nextstate = STM_TYPE_MDIO_WWAIT;	
      end
   STM_TYPE_MDIO_WWAIT:
      begin
      if (mdio_busy == 1'b 0)
         begin
         nextstate = STM_TYPE_NEXT_CYCLE;	
         end
      else
         begin
         nextstate = STM_TYPE_MDIO_WWAIT;	
         end
      end

`ifdef MTIPM10_HOST_CONTROL_PIPE

   STM_TYPE_NEXT_CYCLE:
      begin
      nextstate = STM_TYPE_WAIT_CYCLE;	
      end
   STM_TYPE_WAIT_CYCLE:         // extra output register pipeline wait cycle
      begin
      nextstate = STM_TYPE_IDLE;	
      end

`else

   STM_TYPE_NEXT_CYCLE:
      begin
      nextstate = STM_TYPE_IDLE;	
      end

`endif

   default:
      begin
      nextstate = STM_TYPE_IDLE;	
      end

   endcase
   end

//  Registers Control
//  -----------------                                        
always @(posedge reset or posedge clk)
   begin : process_4
   if (reset == 1'b 1)
      begin
      reg_wr <= 1'b 0;	
      reg_rd <= 1'b 0;	
      stat_rd <= 1'b 0;
      end
   else
      begin

        //  read pulse, or permanent during statistics and MDIO read
      if (nextstate == STM_TYPE_READ | 
          nextstate == STM_TYPE_STAT_READ | 
          nextstate == STM_TYPE_STAT_WAIT | 
          nextstate == STM_TYPE_READ_PHY_STAT1 | 
          nextstate == STM_TYPE_MDIO_READ)
         begin
         reg_rd <= 1'b 1;	
         end
      else
         begin
         reg_rd <= 1'b 0;	
         end

        //  read within statistics address range
      if (nextstate == STM_TYPE_STAT_READ | 
          nextstate == STM_TYPE_STAT_WAIT)
         begin
         stat_rd <= 1'b 1;	
         end
      else
         begin
         stat_rd <= 1'b 0;	
         end

        //  write pulse
      if (nextstate == STM_TYPE_WRITE)
         begin
         reg_wr <= 1'b 1;	//  wr_reg
         end
      else
         begin
         reg_wr <= 1'b 0;	
         end

      end
   end

//  Interface Control
//  -----------------

`ifdef MTIPM10_HOST_CONTROL_PIPE

always @(posedge reset or posedge clk)
   begin : process_5
   if (reset == 1'b 1)
      begin
      data_out <= {32{1'b 0}};	
      end
   else
      begin
      data_out <= reg_data_out;	
      end
   end

always @(posedge reset or posedge clk)
   begin : process_6
   if (reset == 1'b 1)
      begin
      busy <= 1'b 1;	
      end
   else
      begin
      if (nextstate == STM_TYPE_WAIT_CYCLE)     // extra output register pipeline delay
         begin
         busy <= 1'b 0;	
         end
      else
         begin
         busy <= 1'b 1;	
         end
      end
   end

`else   // direct output (reg_data_out is anyway a DFF output already)

always @(reg_data_out)
begin
        data_out = reg_data_out;
end

always @(posedge reset or posedge clk)
   begin : process_6
   if (reset == 1'b 1)
      begin
      busy <= 1'b 1;	
      end
   else
      begin
      if (nextstate == STM_TYPE_NEXT_CYCLE)
         begin
         busy <= 1'b 0;	
         end
      else
         begin
         busy <= 1'b 1;	
         end
      end
   end

`endif // MTIPM10_HOST_CONTROL_PIPE


//  MDIO Module
//  -----------------                                        
always @(posedge reset or posedge clk)
   begin : process_7
   if (reset == 1'b 1)
      begin
      mdio_rd <= 1'b 0;	
      mdio_wr <= 1'b 0;	
      end
   else
      begin
      if (nextstate == STM_TYPE_MDIO_READ)
         begin
         mdio_rd <= 1'b 1;	
         end
      else
         begin
         mdio_rd <= 1'b 0;	
         end
      if (state == STM_TYPE_MDIO_WRITE)
         begin
         mdio_wr <= 1'b 1;	
         end
      else
         begin
         mdio_wr <= 1'b 0;	
         end
      end
   end

//  Status Register Reset
//  ---------------------
always @(posedge reset or posedge clk)
   begin : process_8
   if (reset == 1'b 1)
      begin
      rst_status <= 1'b 0;	
      end
   else
      begin
      if (nextstate == STM_TYPE_READ_PHY_STAT1)
         begin
        //  assert clear at very same time as reg_rd
         rst_status <= 1'b 1;	
         end
      else
         begin
         rst_status <= 1'b 0;	
         end
      end
   end


endmodule // module host_control_xl

